package com.example.shiro;

import com.example.entity.User;
import com.example.service.AuthService;
import com.example.utils.JwtUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.List;

/**
 * @author fyx
 */
public class MyRealm extends AuthorizingRealm {
    private AuthService authService;
    private RedisTemplate<String, Object> redisTemplate;

    public void setAuthService(AuthService authService) {
        this.authService = authService;
    }

    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 取出用户名
        String username = (String) principals.getPrimaryPrincipal();
        // 新建一个授权信息对象
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 写入授权的角色
        List<String> roles = authService.getRoles(username);
        authorizationInfo.addRoles(roles);
        // 写入用户的权限
        authorizationInfo.addStringPermissions(authService.getPerms(roles));
        return authorizationInfo;
    }

    /**
     * 自定义认证
     * 注意需要重写类中的support方法,或者配置类中使用setAuthenticationTokenClass传入自定义token的类型
     * 否则无法进入认证方法
     *
     * @param token 传入的自定义token
     * @return AuthenticationInfo 用于授权使用
     * @throws AuthenticationException 认证异常
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String jwtToken = (String) token.getPrincipal();
        String username = JwtUtils.getUserName(jwtToken);
        // 从redis中取出对应用户的token
        User user = (User) redisTemplate.opsForValue().get(username + "Token");
        if (user == null || !user.getToken().equals(jwtToken)) {
            throw new AuthenticationException("token认证失败");
        }
        return new SimpleAuthenticationInfo(username, token.getCredentials(), "myRealm");
    }
}
